home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Direct3D / ConfigSystem / configdatabase.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-28  |  87.6 KB  |  2,633 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: ConfigDatabase.cpp
  3. //
  4. // Implementation of configuration database object.
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //--------------------------------------------------------------------------------------
  8. #include "dxstdafx.h"
  9. #include <windows.h>
  10. #include <stdio.h>
  11. #include <map>
  12. #include "ConfigDatabase.h"
  13. #define INITGUID
  14. #include <guiddef.h>
  15. #include <dsconf.h>
  16.  
  17.  
  18. DWORD GetHexDigits( WCHAR* ptr )
  19. {
  20.     DWORD val = 0;
  21.     while( ( *ptr >= L'0' && *ptr <= L'9' ) || ( *ptr >= L'a' && *ptr <= L'f' ) )
  22.     {
  23.         val *= 16;
  24.         if( *ptr >= L'0' && *ptr <= L'9' )
  25.             val += *ptr - L'0';
  26.         else
  27.             val += *ptr - L'a' + 10;
  28.  
  29.         ++ptr;
  30.     };
  31.     return val;
  32. }
  33.  
  34.  
  35. void ConvertToLower( WCHAR *psz )
  36. {
  37.     while( *psz != L'\0' )
  38.     {
  39.         if( *psz >= L'A' && *psz <= L'Z' )
  40.             *psz += (L'a' - L'A');
  41.         ++psz;
  42.     }
  43. }
  44.  
  45.  
  46. HRESULT InitSoundInformation( REFGUID DsoundGuid, SOUND_DEVICE *pSndDev )
  47. {
  48.     OSVERSIONINFO vi;
  49.     vi.dwOSVersionInfoSize = sizeof(vi);
  50.     ::GetVersionEx( &vi );
  51.  
  52.     // Obtain the DirectSoundPrivate interface
  53.  
  54.     typedef HRESULT (STDAPICALLTYPE *LPFNDLLGETCLASSOBJECT)(REFCLSID, REFIID, LPVOID *);
  55.  
  56.     HINSTANCE          hLibDsound           = NULL;
  57.     LPFNGETCLASSOBJECT pfnDllGetClassObject = NULL;
  58.     LPCLASSFACTORY     pClassFactory        = NULL;
  59.     LPKSPROPERTYSET    pKsPropertySet       = NULL;
  60.     HRESULT            hr                   = S_OK;
  61.     DWORD              cDevices             = 0;
  62.     DWORD              dwDevNode            = 0;
  63.     WCHAR              wszInterface[512] = L"";
  64.     WCHAR              wszModule[MAX_PATH] = L"";
  65.  
  66.     // Load dsound.dll
  67.     WCHAR wszDllPath[MAX_PATH];
  68.     ::GetSystemDirectory( wszDllPath, MAX_PATH );
  69.     lstrcatW( wszDllPath, L"\\dsound.dll" );
  70.     hLibDsound = LoadLibraryW( wszDllPath );
  71.  
  72.     if( hLibDsound )
  73.     {
  74.         // Find DllGetClassObject
  75.         pfnDllGetClassObject = (LPFNDLLGETCLASSOBJECT)GetProcAddress( hLibDsound, "DllGetClassObject" );
  76.  
  77.         if( pfnDllGetClassObject )
  78.         {
  79.             // Create a class factory object
  80.             hr = pfnDllGetClassObject( CLSID_DirectSoundPrivate, IID_IClassFactory, (LPVOID *)&pClassFactory );
  81.  
  82.             // Create the DirectSoundPrivate object and query for an IKsPropertySet interface
  83.             if( SUCCEEDED(hr) )
  84.             {
  85.                 hr = pClassFactory->CreateInstance( NULL, IID_IKsPropertySet, (LPVOID *)&pKsPropertySet );
  86.  
  87.                 if( pKsPropertySet )
  88.                 {
  89.                     // We have the interface.  Query DSound6 description.
  90.  
  91.                     DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1_DATA  Basic1;
  92.                     PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1_DATA pData1 = NULL;
  93.                     ULONG                                            cbData;
  94.  
  95.                     Basic1.DeviceId = DsoundGuid;
  96.  
  97.                     hr = pKsPropertySet->Get( DSPROPSETID_DirectSoundDevice,
  98.                                               DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1,
  99.                                               NULL,
  100.                                               0,
  101.                                               &Basic1,
  102.                                               sizeof(Basic1),
  103.                                               &cbData );
  104.  
  105.                     if( SUCCEEDED(hr) )
  106.                     {
  107.                         pData1 = (PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1_DATA)malloc(cbData);
  108.  
  109.                         if( !pData1 )
  110.                         {
  111.                             hr = DSERR_OUTOFMEMORY;
  112.                         }
  113.                     }
  114.  
  115.                     if( SUCCEEDED(hr) )
  116.                     {
  117.                         ZeroMemory( pData1, cbData );
  118.  
  119.                         pData1->DeviceId = DsoundGuid;
  120.  
  121.                         hr = pKsPropertySet->Get( DSPROPSETID_DirectSoundDevice,
  122.                                                   DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1,
  123.                                                   NULL,
  124.                                                   0,
  125.                                                   pData1,
  126.                                                   cbData,
  127.                                                   NULL );
  128.  
  129.                         // Fill in the info.
  130.                         dwDevNode = pData1->Devnode;
  131.                     }
  132.  
  133.                     // Free device description memory
  134.                     if( pData1 )
  135.                         ::free( pData1 );
  136.  
  137.                     // Query the DSound7 description
  138.  
  139.                     DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W_DATA  Basic;
  140.                     PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W_DATA pDataW = NULL;
  141.  
  142.                     Basic.DeviceId = DsoundGuid;
  143.  
  144.                     hr = pKsPropertySet->Get( DSPROPSETID_DirectSoundDevice,
  145.                                               DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W,
  146.                                               NULL,
  147.                                               0,
  148.                                               &Basic,
  149.                                               sizeof(Basic),
  150.                                               &cbData );
  151.  
  152.                     if( SUCCEEDED(hr) )
  153.                     {
  154.                         pDataW = (PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W_DATA)malloc(cbData);
  155.  
  156.                         if( !pDataW )
  157.                         {
  158.                             hr = DSERR_OUTOFMEMORY;
  159.                         }
  160.                     }
  161.  
  162.                     if( SUCCEEDED(hr) )
  163.                     {
  164.                         ZeroMemory( pDataW, cbData );
  165.  
  166.                         pDataW->DeviceId = DsoundGuid;
  167.  
  168.                         hr = pKsPropertySet->Get( DSPROPSETID_DirectSoundDevice,
  169.                                                   DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W,
  170.                                                   NULL,
  171.                                                   0,
  172.                                                   pDataW,
  173.                                                   cbData,
  174.                                                   NULL );
  175.  
  176.                         // Fill in the info.
  177.                         wcsncpy( pSndDev->name, pDataW->Description, 64 );
  178.                         pSndDev->name[63] = L'\0';
  179.                         wcsncpy( wszModule, pDataW->Module, MAX_PATH );
  180.                         wszModule[MAX_PATH-1] = L'\0';
  181.  
  182.                         // Obtain the interface path to extract IDs.
  183.                         if( VER_PLATFORM_WIN32_WINDOWS == vi.dwPlatformId )
  184.                         {
  185.                             // Win9x does not return interface path.  It needs to
  186.                             // be fetched from registry.
  187.  
  188.                             HKEY hKey = NULL;
  189.                             HKEY hDevKey;
  190.                             DWORD iKey = 0;
  191.  
  192.                             // On Win9x, we have the DevNode, so find the device in the registry
  193.                             // with the matching DevNode and gather more info there.
  194.                             if( ERROR_SUCCESS == ::RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  195.                                                                  L"System\\CurrentControlSet\\control\\MediaResources\\wave",
  196.                                                                  0, KEY_READ, &hKey ) )
  197.                             {
  198.                                 while( true )
  199.                                 {
  200.                                     WCHAR wszDevKey[MAX_PATH];
  201.  
  202.                                     if( ERROR_SUCCESS != ::RegEnumKey( hKey, iKey, wszDevKey, MAX_PATH ) )
  203.                                         break;
  204.  
  205.                                     if( ERROR_SUCCESS == ::RegOpenKeyEx( hKey, wszDevKey, 0, KEY_READ, &hDevKey ) )
  206.                                     {
  207.                                         DWORD dwDevnode;
  208.                                         DWORD cb;
  209.                                         DWORD dwType;
  210.  
  211.                                         cb = sizeof(dwDevnode);
  212.                                         if( ERROR_SUCCESS == ::RegQueryValueEx( hDevKey, L"DevNode", NULL, &dwType, (BYTE*)&dwDevnode, &cb ) )
  213.                                         {
  214.                                             if( dwDevnode == dwDevNode )
  215.                                             {
  216.                                                 // Found match
  217.                                                 cb = sizeof(wszInterface);
  218.                                                 ::RegQueryValueEx( hDevKey, L"DeviceID", NULL, &dwType, (LPBYTE)wszInterface, &cb );
  219.  
  220.                                                 // Occasionally the driver name that DirectSoundEnumerate spits out
  221.                                                 // is garbage.  If that's the case, use the driver name listed here instead.
  222.                                                 if( lstrlenW(wszModule) < 4 )
  223.                                                 {
  224.                                                     cb = sizeof(wszModule);
  225.                                                     ::RegQueryValueEx( hDevKey, L"Driver", NULL, &dwType, (LPBYTE)wszModule, &cb );
  226.                                                 }
  227.                                             }
  228.                                         }
  229.                                         ::RegCloseKey( hDevKey );
  230.                                     }
  231.                                     iKey++;
  232.                                 }
  233.                                 ::RegCloseKey( hKey );
  234.                             }
  235.                         }
  236.                         else
  237.                         {
  238.                             // Interface string is available on NT
  239.                             wcsncpy( wszInterface, pDataW->Interface, 512 );
  240.                             wszInterface[511] = L'\0';
  241.                         }
  242.                     }
  243.  
  244.                     // Free device description memory
  245.                     if( pDataW )
  246.                         ::free( pDataW );
  247.  
  248.                     // Release the IKsPropertySet interface
  249.                     SAFE_RELEASE( pKsPropertySet );
  250.  
  251.                     // Extract Product/Vendor/Revision/Subsystem IDs from interface string
  252.                     ConvertToLower( wszInterface );
  253.  
  254.                     WCHAR *szPre = wcsstr( wszInterface, L"ven_" );
  255.                     if( szPre )
  256.                         pSndDev->VendorID = GetHexDigits( szPre + 4 );
  257.                     szPre = wcsstr( wszInterface, L"dev_" );
  258.                     if( szPre )
  259.                         pSndDev->DeviceID = GetHexDigits( szPre + 4 );
  260.                     szPre = wcsstr( wszInterface, L"subsys_" );
  261.                     if( szPre )
  262.                         pSndDev->SubSysID = GetHexDigits( szPre + 7 );
  263.                     szPre = wcsstr( wszInterface, L"rev_" );
  264.                     if( szPre )
  265.                         pSndDev->Revision = GetHexDigits( szPre + 4 );
  266.  
  267.                     // Obtain driver version.  Try system dir first, then
  268.                     // try systemDir\drivers.
  269.                     WCHAR wszDriverPath[MAX_PATH];
  270.                     ::GetSystemDirectory( wszDriverPath, MAX_PATH );
  271.                     lstrcatW( wszDriverPath, L"\\" );
  272.                     wcsncat( wszDriverPath, wszModule, MAX_PATH - lstrlenW(wszDriverPath) );
  273.                     wszDriverPath[MAX_PATH - 1] = L'\0';
  274.  
  275.                     // If the file does not exist, use %SystemDir%\drivers.
  276.                     if( INVALID_FILE_ATTRIBUTES == GetFileAttributes( wszDriverPath ) )
  277.                     {
  278.                         ::GetSystemDirectory( wszDriverPath, MAX_PATH );
  279.                         lstrcatW( wszDriverPath, L"\\drivers\\" );
  280.                         wcsncat( wszDriverPath, wszModule, MAX_PATH - lstrlenW(wszDriverPath) );
  281.                         wszDriverPath[MAX_PATH - 1] = L'\0';
  282.                     }
  283.  
  284.                     DWORD dwVerHandle;
  285.                     DWORD dwBufferSize = GetFileVersionInfoSize( wszDriverPath, &dwVerHandle );
  286.                     LPVOID pBuffer = ::malloc( dwBufferSize );
  287.                     VS_FIXEDFILEINFO *pVer;
  288.                     UINT uVerSize;
  289.                     if( dwBufferSize && pBuffer )
  290.                     {
  291.                         if( GetFileVersionInfo( wszDriverPath, dwVerHandle, dwBufferSize, pBuffer ) &&
  292.                             VerQueryValue( pBuffer, L"\\", (LPVOID*)&pVer, &uVerSize ) )
  293.                         {
  294.                             // Retrieve version number
  295.                             pSndDev->DriverVersionLowPart = pVer->dwFileVersionLS;
  296.                             pSndDev->DriverVersionHighPart = pVer->dwFileVersionMS;
  297.                         }
  298.                         ::free( pBuffer );
  299.                     }
  300.                 }
  301.  
  302.                 // Release the class factory
  303.                 SAFE_RELEASE( pClassFactory );
  304.             }
  305.         }
  306.  
  307.         FreeLibrary( hLibDsound );
  308.     }
  309.  
  310.     return hr;
  311. }
  312.  
  313.  
  314. #if 0
  315. DWORD InitSoundInformation( SOUND_DEVICE **ppSndDevs )
  316. {
  317.     DWORD dwCount = 0;
  318.     *ppSndDevs = NULL;
  319.     HDEVINFO hAudioClass;
  320.  
  321.     hAudioClass = SetupDiGetClassDevsA( &KSCATEGORY_AUDIO, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE );
  322.     if( INVALID_HANDLE_VALUE != hAudioClass )
  323.     {
  324.         SP_DEVINFO_DATA sdd;
  325.         sdd.cbSize = sizeof(sdd);
  326.  
  327.         // Find out how many devices there are.
  328.         for( dwCount = 0; ; ++dwCount )
  329.         {
  330.             if( !SetupDiEnumDeviceInfo( hAudioClass, dwCount, &sdd ) )
  331.                 break;
  332.         }
  333.  
  334.         GetLastError();
  335.         // Allocate memory for device list
  336.         DWORD dwReqSize;
  337.         *ppSndDevs = new SOUND_DEVICE[dwCount];
  338.         ZeroMemory( *ppSndDevs, sizeof(SOUND_DEVICE) * dwCount );
  339.  
  340.         if( *ppSndDevs )
  341.         {
  342.             for( DWORD i = 0; i < dwCount; ++i )
  343.             {
  344.                 SetupDiEnumDeviceInfo( hAudioClass, i, &sdd );
  345.                 (*ppSndDevs)[i].DevInst = sdd.DevInst;
  346.  
  347.                 char szBuffer[512];
  348.                 // Get device instance ID
  349.                 SetupDiGetDeviceInstanceIdA( hAudioClass, &sdd, szBuffer, 512, NULL );
  350.                 szBuffer[511] = '\0';
  351.                 ConvertToLowerA( szBuffer );
  352.                 MultiByteToWideChar( CP_ACP, 0, szBuffer, -1, (*ppSndDevs)[i].InstanceID, 512 );
  353.                 (*ppSndDevs)[i].InstanceID[511] = L'\0';
  354.  
  355.                 // Get description
  356.                 SetupDiGetDeviceRegistryPropertyA( hAudioClass, &sdd, SPDRP_DEVICEDESC, NULL, (PBYTE)szBuffer, sizeof(szBuffer), &dwReqSize );
  357.                 MultiByteToWideChar( CP_ACP, 0, szBuffer, -1, (*ppSndDevs)[i].name, 64 );
  358.                 (*ppSndDevs)[i].name[63] = L'\0';
  359.  
  360.                 // Get hardware ID and retrieve vendor and product IDs
  361.                 char *szHwId;
  362.                 SetupDiGetDeviceRegistryPropertyA( hAudioClass, &sdd, SPDRP_HARDWAREID, NULL, NULL, 0, &dwReqSize );
  363.  
  364.                 szHwId = (char *)::malloc( dwReqSize );
  365.                 if( szHwId )
  366.                 {
  367.                     SetupDiGetDeviceRegistryPropertyA( hAudioClass, &sdd, SPDRP_HARDWAREID, NULL, (PBYTE)szHwId, dwReqSize, &dwReqSize );
  368.                     ConvertToLowerA( szHwId );
  369.  
  370.                     char *szPre = strstr( szHwId, "ven_" );
  371.                     if( szPre )
  372.                         (*ppSndDevs)[i].VendorID = GetHexDigitsA( szPre + 4 );
  373.                     szPre = strstr( szHwId, "dev_" );
  374.                     if( szPre )
  375.                         (*ppSndDevs)[i].DeviceID = GetHexDigitsA( szPre + 4 );
  376.                     szPre = strstr( szHwId, "subsys_" );
  377.                     if( szPre )
  378.                         (*ppSndDevs)[i].SubSysID = GetHexDigitsA( szPre + 7 );
  379.                     szPre = strstr( szHwId, "rev_" );
  380.                     if( szPre )
  381.                         (*ppSndDevs)[i].Revision = GetHexDigitsA( szPre + 4 );
  382.  
  383.                     ::free( szHwId );
  384.                 }
  385.  
  386.                 // Obtain driver version
  387.                 char szService[512];
  388.                 if( SetupDiGetDeviceRegistryPropertyA( hAudioClass, &sdd, SPDRP_SERVICE, NULL, (PBYTE)szService, 512, &dwReqSize ) )
  389.                 {
  390.                     // We have the service name.  Retrieve the filename of the service.
  391.  
  392.                     SC_HANDLE hscManager = NULL;
  393.                     SC_HANDLE hscService = NULL;
  394.                     LPQUERY_SERVICE_CONFIGA pqsc = NULL;
  395.  
  396.                     hscManager = OpenSCManagerA( NULL, NULL, GENERIC_READ );
  397.                     if( hscManager )
  398.                     {
  399.                         hscService = OpenServiceA( hscManager, szService, GENERIC_READ );
  400.                         if( hscService )
  401.                         {
  402.                             if( QueryServiceConfigA( hscService, NULL, 0, &dwReqSize ) ||
  403.                                 GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  404.                             {
  405.                                 pqsc = (LPQUERY_SERVICE_CONFIGA)::malloc( dwReqSize );
  406.                                 if( pqsc )
  407.                                 {
  408.                                     QueryServiceConfigA( hscService, pqsc, dwReqSize, &dwReqSize );
  409.                                     char *pLastSlash = strrchr( pqsc->lpBinaryPathName, '\\' );
  410.                                     // Make pLastSlash point to first char of the file name.
  411.                                     if( !pLastSlash )
  412.                                         pLastSlash = pqsc->lpBinaryPathName;
  413.                                     else
  414.                                         ++pLastSlash;
  415.  
  416.                                     WCHAR wszDriverPath[MAX_PATH];
  417.                                     ::GetSystemDirectory( wszDriverPath, MAX_PATH );
  418.                                     lstrcatW( wszDriverPath, L"\\" );
  419.                                     int nPreLen = lstrlenW( wszDriverPath );
  420.                                     // Convert to Unicode and append simultaneously.
  421.                                     MultiByteToWideChar( CP_ACP, 0, pLastSlash, -1, wszDriverPath + nPreLen, MAX_PATH - nPreLen );
  422.                                     wszDriverPath[MAX_PATH - 1] = L'\0';
  423.  
  424.                                     // If the file does not exist, use %SystemDir%\drivers.
  425.                                     if( INVALID_FILE_ATTRIBUTES == GetFileAttributes( wszDriverPath ) )
  426.                                     {
  427.                                         ::GetSystemDirectory( wszDriverPath, MAX_PATH );
  428.                                         lstrcatW( wszDriverPath, L"\\drivers\\" );
  429.                                         nPreLen = lstrlenW( wszDriverPath );
  430.                                         // Convert to Unicode and append simultaneously.
  431.                                         MultiByteToWideChar( CP_ACP, 0, pLastSlash, -1, wszDriverPath + nPreLen, MAX_PATH - nPreLen );
  432.                                         wszDriverPath[MAX_PATH - 1] = L'\0';
  433.                                     }
  434.  
  435.                                     DWORD dwVerHandle;
  436.                                     DWORD dwBufferSize = GetFileVersionInfoSize( wszDriverPath, &dwVerHandle );
  437.                                     LPVOID pBuffer = ::malloc( dwBufferSize );
  438.                                     VS_FIXEDFILEINFO *pVer;
  439.                                     UINT uVerSize;
  440.                                     if( pBuffer )
  441.                                     {
  442.                                         if( GetFileVersionInfo( wszDriverPath, dwVerHandle, dwBufferSize, pBuffer ) &&
  443.                                             VerQueryValue( pBuffer, L"\\", (LPVOID*)&pVer, &uVerSize ) )
  444.                                         {
  445.                                             // Retrieve version number
  446.                                             (*ppSndDevs)[i].DriverVersionLowPart = pVer->dwFileVersionLS;
  447.                                             (*ppSndDevs)[i].DriverVersionHighPart = pVer->dwFileVersionMS;
  448.                                         }
  449.                                         ::free( pBuffer );
  450.                                     }
  451.  
  452.                                     ::free( pqsc );
  453.                                 }
  454.                             }
  455.                             CloseServiceHandle( hscService );
  456.                         }
  457.                         CloseServiceHandle( hscManager );
  458.                     }
  459.                 }
  460.             }
  461.         }
  462.  
  463.         SetupDiDestroyDeviceInfoList( hAudioClass );
  464.     }
  465.     GetLastError();
  466.  
  467.     return dwCount;
  468. }
  469. #endif
  470.  
  471.  
  472.     class CConfigDatabase;
  473.  
  474.     const char k_KeywordDisplayVendor[]             = "displayvendor";
  475.     const char k_KeywordAudioVendor[]               = "audiovendor";
  476.     const char k_KeywordApplyToAll[]                = "applytoall";
  477.     const char k_KeywordRequirements[]              = "Requirements";
  478.     const char k_KeywordPropertySet[]               = "propertyset";
  479.     const char k_KeywordIf[]                        = "if";
  480.     const char k_KeywordEndif[]                     = "endif";
  481.     const char k_KeywordRam[]                       = "ram";
  482.     const char k_KeywordVideoram[]                  = "videoram";
  483.     const char k_KeywordSubsysid[]                  = "subsysid";
  484.     const char k_KeywordRevision[]                  = "revision";
  485.     const char k_KeywordDriver[]                    = "driver";
  486.     const char k_KeywordGuid[]                      = "guid";
  487.     const char k_KeywordOs[]                        = "os";
  488.     const char k_KeywordWin95[]                     = "win95";
  489.     const char k_KeywordWin98[]                     = "win98";
  490.     const char k_KeywordWin98se[]                   = "win98se";
  491.     const char k_KeywordWinme[]                     = "winme";
  492.     const char k_KeywordWin2k[]                     = "win2k";
  493.     const char k_KeywordWinxp[]                     = "winxp";
  494.     const char k_KeywordWin2003[]                   = "win2003";
  495.     const char k_KeywordBreak[]                     = "break";
  496.     const char k_KeywordUnknown[]                   = "unknown";
  497.     const char k_KeywordCaps[]                      = "Caps";
  498.     const char k_KeywordCaps2[]                     = "Caps2";
  499.     const char k_KeywordCaps3[]                     = "Caps3";
  500.     const char k_KeywordPresentationIntervals[]     = "PresentationIntervals";
  501.     const char k_KeywordCursorCaps[]                = "CursorCaps";
  502.     const char k_KeywordDevCaps[]                   = "DevCaps";
  503.     const char k_KeywordPrimitiveMiscCaps[]         = "PrimitiveMiscCaps";
  504.     const char k_KeywordRasterCaps[]                = "RasterCaps";
  505.     const char k_KeywordZCmpCaps[]                  = "ZCmpCaps";
  506.     const char k_KeywordSrcBlendCaps[]              = "SrcBlendCaps";
  507.     const char k_KeywordDestBlendCaps[]             = "DestBlendCaps";
  508.     const char k_KeywordAlphaCmpCaps[]              = "AlphaCmpCaps";
  509.     const char k_KeywordShadeCaps[]                 = "ShadeCaps";
  510.     const char k_KeywordTextureCaps[]               = "TextureCaps";
  511.     const char k_KeywordTextureFilterCaps[]         = "TextureFilterCaps";
  512.     const char k_KeywordCubeTextureFilterCaps[]     = "CubeTextureFilterCaps";
  513.     const char k_KeywordVolumeTextureFilterCaps[]   = "VolumeTextureFilterCaps";
  514.     const char k_KeywordTextureAddressCaps[]        = "TextureAddressCaps";
  515.     const char k_KeywordVolumeTextureAddressCaps[]  = "VolumeTextureAddressCaps";
  516.     const char k_KeywordLineCaps[]                  = "LineCaps";
  517.     const char k_KeywordMaxTextureWidth[]           = "MaxTextureWidth";
  518.     const char k_KeywordMaxTextureHeight[]          = "MaxTextureHeight";
  519.     const char k_KeywordMaxVolumeExtent[]           = "MaxVolumeExtent";
  520.     const char k_KeywordMaxTextureRepeat[]          = "MaxTextureRepeat";
  521.     const char k_KeywordMaxTextureAspectRatio[]     = "MaxTextureAspectRatio";
  522.     const char k_KeywordMaxAnisotropy[]             = "MaxAnisotropy";
  523.     const char k_KeywordStencilCaps[]               = "StencilCaps";
  524.     const char k_KeywordFVFCaps[]                   = "FVFCaps";
  525.     const char k_KeywordTextureOpCaps[]             = "TextureOpCaps";
  526.     const char k_KeywordMaxTextureBlendStages[]     = "MaxTextureBlendStages";
  527.     const char k_KeywordMaxSimultaneousTextures[]   = "MaxSimultaneousTextures";
  528.     const char k_KeywordVertexProcessingCaps[]      = "VertexProcessingCaps";
  529.     const char k_KeywordMaxActiveLights[]           = "MaxActiveLights";
  530.     const char k_KeywordMaxUserClipPlanes[]         = "MaxUserClipPlanes";
  531.     const char k_KeywordMaxVertexBlendMatrices[]    = "MaxVertexBlendMatrices";
  532.     const char k_KeywordMaxVertexBlendMatrixIndex[] = "MaxVertexBlendMatrixIndex";
  533.     const char k_KeywordMaxPrimitiveCount[]         = "MaxPrimitiveCount";
  534.     const char k_KeywordMaxVertexIndex[]            = "MaxVertexIndex";
  535.     const char k_KeywordMaxStreams[]                = "MaxStreams";
  536.     const char k_KeywordMaxStreamStride[]           = "MaxStreamStride";
  537.     const char k_KeywordVertexShaderVersion[]       = "VertexShaderVersion";
  538.     const char k_KeywordMaxVertexShaderConst[]      = "MaxVertexShaderConst";
  539.     const char k_KeywordPixelShaderVersion[]        = "PixelShaderVersion";
  540.     const char k_KeywordCPUSpeed[]                  = "cpuspeed";
  541.     const char k_KeywordOverallGraphicDetail[]      = "OverallGraphicDetail";
  542.     const char k_KeywordMaxOverallGraphicDetail[]   = "MaxOverallGraphicDetail";
  543.  
  544.  
  545.     //------------------------------------------------------------------------------
  546.     //
  547.     // CPropertySet
  548.     //
  549.     //------------------------------------------------------------------------------
  550.     struct CPropertySet
  551.     {
  552.     private:
  553.         std::vector<StringPair> m_Properties;
  554.         const CConfigDatabase& m_Owner;
  555.     public:
  556.         CPropertySet(const CConfigDatabase& );
  557.         void Set(const char* Property, const char * Value);
  558.         bool Get(const char* Property, char* Value, int cbValue);
  559.         const std::vector<StringPair>& GetProperties() const {return m_Properties;}
  560.     };
  561.  
  562.     CPropertySet::CPropertySet(const CConfigDatabase& owner) : m_Owner(owner)
  563.     {
  564.  
  565.     }
  566.  
  567.     void CPropertySet::Set(const char* Property, const char* Value)
  568.     {
  569.         std::vector<StringPair>::iterator it, end;
  570.         it = m_Properties.begin();
  571.         end = m_Properties.end();
  572.         while (it != end)
  573.         {
  574.             StringPair& pr = *it;
  575.             if (0 == _stricmp(pr.first.c_str(), Property))
  576.             {
  577.                 pr.second = Value;
  578.                 return;
  579.             }
  580.             ++it;
  581.         }
  582.         m_Properties.push_back(StringPair(std::string(Property), std::string(Value)));
  583.     }
  584.  
  585.     bool CPropertySet::Get(const char* Property, char* Value, int cbValue)
  586.     {
  587.         std::vector<StringPair>::iterator it, end;
  588.         it = m_Properties.begin();
  589.         end = m_Properties.end();
  590.         while (it != end)
  591.         {
  592.             StringPair& pr = *it;
  593.             if (0 == _stricmp(pr.first.c_str(), Property))
  594.             {
  595.                 strncpy(Value, pr.second.c_str(), cbValue);
  596.                 return true;
  597.             }
  598.             ++it;
  599.         }
  600.         return false;
  601.     }
  602.  
  603.     //--------------------------------------------------------------------------------
  604.     //
  605.     // CConfigDatabase
  606.     //
  607.     //---------------------------------------------------------------------------------
  608.     class CConfigDatabase : public IConfigDatabase
  609.     {
  610.     public:
  611.         CConfigDatabase();
  612.         ~CConfigDatabase();
  613.  
  614.         //
  615.         // IConfigDatabase
  616.         //
  617.         bool Load( WCHAR* FileName, const SOUND_DEVICE& soundDevice, const D3DADAPTER_IDENTIFIER9& DDid, const D3DCAPS9&, DWORD SystemMemory, DWORD VideoMemory, DWORD CPUSpeed );
  618.         void Release() {delete this;};
  619.  
  620.         unsigned int GetDevicePropertyCount() const { return (int)m_pDevice->GetProperties().size(); }
  621.         const char* GetDeviceProperty(unsigned int i) const {return m_pDevice->GetProperties().at(i).first.c_str(); }
  622.         const char* GetDeviceValue(unsigned int i) const { return m_pDevice->GetProperties().at(i).second.c_str(); }
  623.  
  624.         unsigned int GetRequirementsPropertyCount() const { return (int)m_pRequirements->GetProperties().size(); }
  625.         const char* GetRequirementsProperty(unsigned int i) const { return m_pRequirements->GetProperties().at(i).first.c_str(); }
  626.         const char* GetRequirementsValue(unsigned int i) const { return m_pRequirements->GetProperties().at(i).second.c_str(); }
  627.  
  628. #ifdef ICONFIGDATABASE_USE_STL
  629.         const std::vector<StringPair>& GetAggregateProperties() const { return m_pDevice->GetProperties(); }
  630.         const std::vector<StringPair>* GetNamedProperties(const char* ) const;
  631. #endif
  632.         const char* GetGfxDeviceString() const { return m_DeviceString.c_str(); }
  633.         const char* GetGfxVendorString() const { return m_VendorString.c_str(); }
  634.         const char* GetSoundDeviceString() const { return m_SoundDeviceString.c_str(); }
  635.         const char* GetSoundVendorString() const { return m_SoundVendorString.c_str(); }
  636.  
  637.         bool IsError() const { return m_fError; }
  638.         const char* GetErrorString() const { return m_ErrorString.c_str(); }
  639.  
  640.     private:
  641.  
  642.         //
  643.         //
  644.         // Variables use to read in file
  645.         //
  646.         //
  647.         char* m_pchFile;                            // Pointer to start of file
  648.         char* m_pchCurrent;                         // Current file pointer
  649.         char* m_pchEndOfFile;                       // Pointer to the end of file
  650.         char* m_pchCurrentLine;                     // Pointer to start of this line
  651.         DWORD m_LineNumber;                         // Line Number
  652.  
  653.         CPropertySet* m_pDevice;
  654.         CPropertySet* m_pRequirements;
  655.  
  656.         bool m_fError;                              // Errors adding strings
  657.         std::string m_ErrorString;
  658.  
  659.         std::string m_DeviceString;
  660.         std::string m_VendorString;
  661.         std::string m_SoundDeviceString;
  662.         std::string m_SoundVendorString;
  663.  
  664.         DWORD m_CPUSpeed;                           // CPU Speed passed in
  665.         DWORD m_SystemMemory;                       // System memory passed in
  666.         DWORD m_VideoMemory;                        // Video memory passed in
  667.         D3DADAPTER_IDENTIFIER9 m_AdapterId;         // DDiD passed in
  668.         D3DCAPS9 m_caps;
  669.  
  670.         SOUND_DEVICE m_SoundDevice;
  671.  
  672.         std::map<std::string, CPropertySet*> m_mapNameToPropertySet;
  673.         std::map<std::string, CPropertySet*> m_mapOGDToPropertySet; //OGD==OverallGraphicDetail
  674.  
  675.         void SkipToNextLine();
  676.         void SkipSpace();
  677.         void SyntaxError( char* ErrorText );
  678.         char* AddFlag(CPropertySet* pPropertySet);
  679.         DWORD GetDigit();
  680.         DWORD GetNumber();
  681.         char* GetString();
  682.         DWORD Get4Digits();
  683.         DWORD sGet4Digits();
  684.         char* GetCondition();
  685.         bool DoDisplayVendorAndDevice();
  686.         bool DoSoundVendorAndDevice();
  687.         bool DoPropertySet(CPropertySet* pPropertySet);
  688.         bool DoPropertySets();
  689.         bool DoRequirements();
  690.         void ApplyPropertySet(CPropertySet* pSetDst, CPropertySet* pSetSrc);
  691.         bool DoPreApplyToAll();
  692.         bool DoPostApplyToAll();
  693.         bool NextStringIs(const char* psz);
  694.     };
  695.  
  696.     const std::vector<StringPair>* CConfigDatabase::GetNamedProperties(const char* pszName) const
  697.     {
  698.         std::string strName(pszName);
  699.         std::map<std::string, CPropertySet*>::const_iterator it;
  700.         it = m_mapNameToPropertySet.find(strName);
  701.         if (it == m_mapNameToPropertySet.end())
  702.         {
  703.             return NULL;
  704.         }
  705.         CPropertySet* pSet = (*it).second;
  706.         return &pSet->GetProperties();
  707.     }
  708.  
  709.  
  710.     //
  711.     // Skip to start of next line
  712.     //
  713.     void CConfigDatabase::SkipToNextLine()
  714.     {
  715.         do
  716.         {
  717.             m_pchCurrent++;
  718.         } while( *(m_pchCurrent-1)!=13 && m_pchCurrent<m_pchEndOfFile );
  719.  
  720.         if( m_pchCurrent<m_pchEndOfFile && *m_pchCurrent==10 )
  721.         {
  722.             m_pchCurrent++;
  723.         }
  724.  
  725.         m_pchCurrentLine=m_pchCurrent;
  726.         m_LineNumber++;
  727.     }
  728.  
  729.     //
  730.     // Skip over blank spaces
  731.     //
  732.     void CConfigDatabase::SkipSpace()
  733.     {
  734.         while( *m_pchCurrent==' ' || *m_pchCurrent==9 )
  735.             m_pchCurrent++;
  736.     }
  737.  
  738.     //
  739.     // Generic syntax error
  740.     //
  741.     void CConfigDatabase::SyntaxError( char* ErrorText )
  742.     {
  743.         if( !m_fError )
  744.         {
  745.             char tempBuffer[40];
  746.             char* dest=tempBuffer;
  747.             char* source=m_pchCurrentLine;
  748.             while( *source!=13 && dest!=&tempBuffer[36] )
  749.             {
  750.                 *dest++=*source++;          // Copy current line into error buffer
  751.             }
  752.             if( dest==&tempBuffer[36] )
  753.             {
  754.                 *dest++='.';
  755.                 *dest++='.';
  756.                 *dest++='.';
  757.             }
  758.             *dest=0;
  759.  
  760.             const size_t k_cchBuffer = 256;
  761.             char Buffer[k_cchBuffer];
  762.             _snprintf( Buffer, k_cchBuffer, "%s on line %d - '%s'", ErrorText, m_LineNumber, tempBuffer );
  763.             Buffer[k_cchBuffer-1] = 0;
  764.             m_ErrorString = Buffer;
  765.             m_fError=1;
  766.         }
  767.     }
  768.  
  769.     //
  770.     // Return a hex digit -1=m_fError  and move pointer on
  771.     //
  772.     DWORD CConfigDatabase::GetDigit()
  773.     {
  774.         DWORD result=-1;
  775.  
  776.         if( *m_pchCurrent>='0' && *m_pchCurrent<='9' )
  777.         {
  778.             result=(DWORD)(*m_pchCurrent++)-'0';
  779.         }
  780.         else
  781.         {
  782.             if( *m_pchCurrent>='a' && *m_pchCurrent<='f' )
  783.             {
  784.                 result=(DWORD)(*m_pchCurrent++)-'a'+10;
  785.             }
  786.             else
  787.             {
  788.                 if( *m_pchCurrent>='A' && *m_pchCurrent<='F' )
  789.                 {
  790.                     result=(DWORD)(*m_pchCurrent++)-'A'+10;
  791.                 }
  792.             }
  793.         }
  794.  
  795.         return result;
  796.     }
  797.  
  798.     //
  799.     // A number is expected, get it - return -1 for error
  800.     //
  801.     DWORD CConfigDatabase::GetNumber()
  802.     {
  803.         DWORD result;
  804.  
  805.         SkipSpace();
  806.  
  807.         if( *(WORD*)m_pchCurrent!='x0' )
  808.         {
  809.             if( *m_pchCurrent>='0' && *m_pchCurrent<='9' )
  810.             {
  811.                 //
  812.                 // Decimal number
  813.                 //
  814.                 result=GetDigit();
  815.  
  816.                 if( result==-1 )
  817.                 {
  818.                     SyntaxError( "Number expected" );
  819.                     return -1;
  820.                 }
  821.  
  822.                 while( *m_pchCurrent>='0' && *m_pchCurrent<='9' )
  823.                 {
  824.                     DWORD tmp=GetDigit();
  825.                     if( tmp==-1 )
  826.                         break;
  827.  
  828.                     if( result>=16602069666338596456 )
  829.                     {
  830.                         SyntaxError( "Number too large" );      
  831.                         return -1;
  832.                     }
  833.  
  834.                     result=result*10+tmp;
  835.                 }
  836.  
  837.                 SkipSpace();
  838.  
  839.                 return result;
  840.  
  841.             }
  842.             else
  843.             {
  844.                 SyntaxError( "Number expected" );       
  845.                 return -1;
  846.             }
  847.         }
  848.         //
  849.         // Hex number?
  850.         //
  851.         m_pchCurrent+=2;
  852.  
  853.         DWORD tmp=GetDigit();
  854.  
  855.         if( tmp==-1 )
  856.         {
  857.             SyntaxError( "Number expected" );
  858.             return -1;
  859.         }
  860.  
  861.         result = 0;
  862.  
  863.         DWORD hexcount = 0;
  864.         do
  865.         {
  866.             if( hexcount>=8 )
  867.             {
  868.                 SyntaxError( "Number too large" );      
  869.                 return -1;
  870.             }
  871.  
  872.             result=result*16+tmp;
  873.             ++hexcount;
  874.             tmp = GetDigit();
  875.         } while (tmp != -1);
  876.  
  877.         SkipSpace();
  878.  
  879.         return result;
  880.     }
  881.  
  882.     //
  883.     // A string is expected, get it - return 0 for error
  884.     //
  885.     char* CConfigDatabase::GetString()
  886.     {
  887.         static char Buffer[256];
  888.  
  889.         SkipSpace();
  890.  
  891.         if( *m_pchCurrent++!='"' )
  892.         {
  893.             SyntaxError( "Expecting """ );      
  894.             return 0;
  895.         }   
  896.  
  897.         char* dest=Buffer;
  898.  
  899.         while( *m_pchCurrent!='"' )
  900.         {
  901.             *dest++=*m_pchCurrent++;
  902.  
  903.             if( dest>&Buffer[255] )
  904.             {
  905.                 SyntaxError( "String too long" );       
  906.                 return 0;
  907.             }   
  908.         }
  909.  
  910.         *dest=0;
  911.         m_pchCurrent++;
  912.  
  913.         SkipSpace();
  914.  
  915.         return Buffer;
  916.     }
  917.  
  918.     //
  919.     // Pointing at a flag = value line, add to the flags being returned
  920.     //
  921.     char* CConfigDatabase::AddFlag(CPropertySet* pPropertySet)
  922.     {
  923.         char Flag[256];
  924.         char* dest=Flag;
  925.  
  926.         while( *m_pchCurrent!=' ' && *m_pchCurrent!='=' && *m_pchCurrent!=13 )
  927.         {
  928.             char chr=*m_pchCurrent++;
  929.  
  930.             if( chr>='A' && chr<='Z' )
  931.                 chr+='a'-'A';                   // Convert to lower case
  932.  
  933.             *dest++=chr;
  934.  
  935.             if( dest==&Flag[254] )
  936.             {
  937.                 return "Flag too long";
  938.             }                       
  939.         }
  940.         *dest=0;
  941.  
  942.         SkipSpace();
  943.  
  944.         char Value[256];
  945.         dest=Value;
  946.  
  947.         if( *m_pchCurrent!=13 )
  948.         {
  949.             if( *m_pchCurrent!='=' )
  950.             {
  951.                 return "flag = xxx expected";
  952.             }
  953.  
  954.             m_pchCurrent++;
  955.             SkipSpace();
  956.  
  957.             if( *m_pchCurrent=='"' )
  958.             {
  959.                 do
  960.                 {
  961.                     char chr=*m_pchCurrent++;
  962.  
  963.                     *dest++=chr;
  964.  
  965.                     if( dest==&Value[254] )
  966.                     {
  967.                         return "Flag too long";
  968.                     }                       
  969.  
  970.                 } while( *m_pchCurrent!='"' && *m_pchCurrent!=13 );
  971.  
  972.                 if( *m_pchCurrent!='"' )
  973.                 {
  974.                     return "Missing Quote";
  975.                 }
  976.  
  977.                 *dest++='"';
  978.  
  979.                 if( dest==&Value[254] )
  980.                 {
  981.                     return "Flag too long";
  982.                 }                       
  983.             }
  984.             else
  985.             {
  986.                 while( *m_pchCurrent!=' ' && *m_pchCurrent!=13 )
  987.                 {
  988.                     char chr=*m_pchCurrent++;
  989.  
  990.                     if( chr>='A' && chr<='Z' )
  991.                         chr+='a'-'A';                   // Convert to lower case
  992.  
  993.                     *dest++=chr;
  994.  
  995.                     if( dest==&Value[254] )
  996.                     {
  997.                         return "Flag too long";
  998.                     }                       
  999.                 }
  1000.             }
  1001.         }
  1002.         *dest=0;
  1003.  
  1004.         pPropertySet->Set(Flag, Value);
  1005.  
  1006.         //  Check for OverallGraphicDetail. This is a special keyword. It is
  1007.         //  used to add this property set to another map.
  1008.         if (_stricmp(k_KeywordOverallGraphicDetail, Flag) == 0)
  1009.             m_mapOGDToPropertySet[Value] = pPropertySet;
  1010.  
  1011.         return 0;
  1012.     }
  1013.  
  1014.     //
  1015.     // Return true if the character is not a alphanumeric
  1016.     //
  1017.     bool NotAscii( char Chr )
  1018.     {
  1019.         if( Chr=='>' || Chr=='<' || Chr=='!' || Chr=='=' || Chr==' ' || Chr==13 || Chr==9 )
  1020.             return true;
  1021.  
  1022.         return false;
  1023.     }
  1024.  
  1025.     //
  1026.     // Returns the next 4 hex digits, -1 if any errors
  1027.     //
  1028.     DWORD CConfigDatabase::Get4Digits()
  1029.     {
  1030.         DWORD result;
  1031.  
  1032.         DWORD tmp=GetDigit();
  1033.  
  1034.         if( tmp==-1 )
  1035.             return -1;
  1036.  
  1037.         result=tmp<<12;
  1038.  
  1039.         tmp=GetDigit();
  1040.  
  1041.         if( tmp==-1 )
  1042.             return -1;
  1043.  
  1044.         result|=tmp<<8;
  1045.  
  1046.         tmp=GetDigit();
  1047.  
  1048.         if( tmp==-1 )
  1049.             return -1;
  1050.  
  1051.         result|=tmp<<4;
  1052.  
  1053.         tmp=GetDigit();
  1054.  
  1055.         if( tmp==-1 )
  1056.             return -1;
  1057.  
  1058.         result|=tmp;
  1059.  
  1060.         return result;
  1061.     }
  1062.  
  1063.     //
  1064.     // Returns the next 4 hex digits, -1 if any errors - SWAPPED version (for guids)
  1065.     //
  1066.     DWORD CConfigDatabase::sGet4Digits()
  1067.     {
  1068.         DWORD temp=Get4Digits();
  1069.  
  1070.         if( temp==-1 )
  1071.             return temp;
  1072.  
  1073.         return ((temp&0xff00)>>8) + ((temp&0xff)<<8);
  1074.     }
  1075.  
  1076.     bool CConfigDatabase::NextStringIs(const char* psz)
  1077.     {
  1078.         int cch = (int)strlen(psz);
  1079.         return (0==_strnicmp( m_pchCurrent, psz, cch ) && NotAscii(m_pchCurrent[cch]));
  1080.     }
  1081.  
  1082.     //
  1083.     // Evaluate an IF condition
  1084.     //
  1085.     // 1=True, 0=False, n=m_fError message
  1086.     //
  1087.     //
  1088.     char* CConfigDatabase::GetCondition()
  1089.     {
  1090.         DWORD Source=0;
  1091.         DWORD Type=0;       // 0=Value, 1=GUID, 2=Driver, 3=os
  1092.         DWORD Compare=0;    // 0 ==,    1 !=,   2 >,   3 <,   4 >=,    5 <=
  1093.  
  1094.         SkipSpace();
  1095.  
  1096.         if( NextStringIs(k_KeywordCPUSpeed))
  1097.         {
  1098.             Source=m_CPUSpeed;
  1099.             m_pchCurrent+=strlen(k_KeywordCPUSpeed);
  1100.         }
  1101.         else if( NextStringIs(k_KeywordRam))
  1102.         {
  1103.             Source=m_SystemMemory;
  1104.             m_pchCurrent+=strlen(k_KeywordRam);
  1105.         }
  1106.         else if ( NextStringIs(k_KeywordCaps))
  1107.         {
  1108.             Source=m_caps.Caps;
  1109.             m_pchCurrent+=strlen(k_KeywordCaps);
  1110.         }
  1111.         else if ( NextStringIs(k_KeywordCaps2))
  1112.         {
  1113.             Source=m_caps.Caps2;
  1114.             m_pchCurrent+=strlen(k_KeywordCaps2);
  1115.         }
  1116.         else if ( NextStringIs(k_KeywordCaps3))
  1117.         {
  1118.             Source=m_caps.Caps3;
  1119.             m_pchCurrent+=strlen(k_KeywordCaps3);
  1120.         }
  1121.         else if ( NextStringIs(k_KeywordPresentationIntervals))
  1122.         {
  1123.             Source=m_caps.PresentationIntervals;
  1124.             m_pchCurrent+=strlen(k_KeywordPresentationIntervals);
  1125.         }
  1126.         else if ( NextStringIs(k_KeywordCursorCaps))
  1127.         {
  1128.             Source=m_caps.CursorCaps;
  1129.             m_pchCurrent+=strlen(k_KeywordCursorCaps);
  1130.         }
  1131.         else if ( NextStringIs(k_KeywordDevCaps))
  1132.         {
  1133.             Source=m_caps.DevCaps;
  1134.             m_pchCurrent+=strlen(k_KeywordDevCaps);
  1135.         }
  1136.         else if ( NextStringIs(k_KeywordPrimitiveMiscCaps))
  1137.         {
  1138.             Source=m_caps.PrimitiveMiscCaps;
  1139.             m_pchCurrent+=strlen(k_KeywordPrimitiveMiscCaps);
  1140.         }
  1141.         else if ( NextStringIs(k_KeywordRasterCaps))
  1142.         {
  1143.             Source=m_caps.RasterCaps;
  1144.             m_pchCurrent+=strlen(k_KeywordRasterCaps);
  1145.         }
  1146.         else if ( NextStringIs(k_KeywordZCmpCaps))
  1147.         {
  1148.             Source=m_caps.ZCmpCaps;
  1149.             m_pchCurrent+=strlen(k_KeywordZCmpCaps);
  1150.         }
  1151.         else if ( NextStringIs(k_KeywordSrcBlendCaps))
  1152.         {
  1153.             Source=m_caps.SrcBlendCaps;
  1154.             m_pchCurrent+=strlen(k_KeywordSrcBlendCaps);
  1155.         }
  1156.         else if ( NextStringIs(k_KeywordDestBlendCaps))
  1157.         {
  1158.             Source=m_caps.DestBlendCaps;
  1159.             m_pchCurrent+=strlen(k_KeywordDestBlendCaps);
  1160.         }
  1161.         else if ( NextStringIs(k_KeywordAlphaCmpCaps))
  1162.         {
  1163.             Source=m_caps.AlphaCmpCaps;
  1164.             m_pchCurrent+=strlen(k_KeywordAlphaCmpCaps);
  1165.         }
  1166.         else if ( NextStringIs(k_KeywordShadeCaps))
  1167.         {
  1168.             Source=m_caps.ShadeCaps;
  1169.             m_pchCurrent+=strlen(k_KeywordShadeCaps);
  1170.         }
  1171.         else if ( NextStringIs(k_KeywordTextureCaps))
  1172.         {
  1173.             Source=m_caps.TextureCaps;
  1174.             m_pchCurrent+=strlen(k_KeywordTextureCaps);
  1175.         }
  1176.         else if ( NextStringIs(k_KeywordTextureFilterCaps))
  1177.         {
  1178.             Source=m_caps.TextureFilterCaps;
  1179.             m_pchCurrent+=strlen(k_KeywordTextureFilterCaps);
  1180.         }
  1181.         else if ( NextStringIs(k_KeywordCubeTextureFilterCaps))
  1182.         {
  1183.             Source=m_caps.CubeTextureFilterCaps;
  1184.             m_pchCurrent+=strlen(k_KeywordCubeTextureFilterCaps);
  1185.         }
  1186.         else if ( NextStringIs(k_KeywordVolumeTextureFilterCaps))
  1187.         {
  1188.             Source=m_caps.VolumeTextureFilterCaps;
  1189.             m_pchCurrent+=strlen(k_KeywordVolumeTextureFilterCaps);
  1190.         }
  1191.         else if ( NextStringIs(k_KeywordTextureAddressCaps))
  1192.         {
  1193.             Source=m_caps.TextureAddressCaps;
  1194.             m_pchCurrent+=strlen(k_KeywordTextureAddressCaps);
  1195.         }
  1196.         else if ( NextStringIs(k_KeywordVolumeTextureAddressCaps))
  1197.         {
  1198.             Source=m_caps.VolumeTextureAddressCaps;
  1199.             m_pchCurrent+=strlen(k_KeywordVolumeTextureAddressCaps);
  1200.         }
  1201.         else if ( NextStringIs(k_KeywordLineCaps))
  1202.         {
  1203.             Source=m_caps.LineCaps;
  1204.             m_pchCurrent+=strlen(k_KeywordLineCaps);
  1205.         }
  1206.         else if ( NextStringIs(k_KeywordMaxTextureWidth))
  1207.         {
  1208.             Source=m_caps.MaxTextureWidth;
  1209.             m_pchCurrent+=strlen(k_KeywordMaxTextureWidth);
  1210.         }
  1211.         else if ( NextStringIs(k_KeywordMaxVolumeExtent))
  1212.         {
  1213.             Source=m_caps.MaxVolumeExtent;
  1214.             m_pchCurrent+=strlen(k_KeywordMaxVolumeExtent);
  1215.         }
  1216.         else if ( NextStringIs(k_KeywordMaxTextureRepeat))
  1217.         {
  1218.             Source=m_caps.MaxTextureRepeat;
  1219.             m_pchCurrent+=strlen(k_KeywordMaxTextureRepeat);
  1220.         }
  1221.         else if ( NextStringIs(k_KeywordMaxTextureAspectRatio))
  1222.         {
  1223.             Source=m_caps.MaxTextureAspectRatio;
  1224.             m_pchCurrent+=strlen(k_KeywordMaxTextureAspectRatio);
  1225.         }
  1226.         else if ( NextStringIs(k_KeywordMaxAnisotropy))
  1227.         {
  1228.             Source=m_caps.MaxAnisotropy;
  1229.             m_pchCurrent+=strlen(k_KeywordMaxAnisotropy);
  1230.         }
  1231.         else if ( NextStringIs(k_KeywordStencilCaps))
  1232.         {
  1233.             Source=m_caps.StencilCaps;
  1234.             m_pchCurrent+=strlen(k_KeywordStencilCaps);
  1235.         }
  1236.         else if ( NextStringIs(k_KeywordFVFCaps))
  1237.         {
  1238.             Source=m_caps.FVFCaps;
  1239.             m_pchCurrent+=strlen(k_KeywordFVFCaps);
  1240.         }
  1241.         else if ( NextStringIs(k_KeywordTextureOpCaps))
  1242.         {
  1243.             Source=m_caps.TextureOpCaps;
  1244.             m_pchCurrent+=strlen(k_KeywordTextureOpCaps);
  1245.         }
  1246.         else if ( NextStringIs(k_KeywordMaxTextureBlendStages))
  1247.         {
  1248.             Source=m_caps.MaxTextureBlendStages;
  1249.             m_pchCurrent+=strlen(k_KeywordMaxTextureBlendStages);
  1250.         }
  1251.         else if ( NextStringIs(k_KeywordMaxSimultaneousTextures))
  1252.         {
  1253.             Source=m_caps.MaxSimultaneousTextures;
  1254.             m_pchCurrent+=strlen(k_KeywordMaxSimultaneousTextures);
  1255.         }
  1256.         else if ( NextStringIs(k_KeywordVertexProcessingCaps))
  1257.         {
  1258.             Source=m_caps.VertexProcessingCaps;
  1259.             m_pchCurrent+=strlen(k_KeywordVertexProcessingCaps);
  1260.         }
  1261.         else if ( NextStringIs(k_KeywordMaxActiveLights))
  1262.         {
  1263.             Source=m_caps.MaxActiveLights;
  1264.             m_pchCurrent+=strlen(k_KeywordMaxActiveLights);
  1265.         }
  1266.         else if ( NextStringIs(k_KeywordMaxUserClipPlanes))
  1267.         {
  1268.             Source=m_caps.MaxUserClipPlanes;
  1269.             m_pchCurrent+=strlen(k_KeywordMaxUserClipPlanes);
  1270.         }
  1271.         else if ( NextStringIs(k_KeywordMaxVertexBlendMatrices))
  1272.         {
  1273.             Source=m_caps.MaxVertexBlendMatrices;
  1274.             m_pchCurrent+=strlen(k_KeywordMaxVertexBlendMatrices);
  1275.         }
  1276.         else if ( NextStringIs(k_KeywordMaxVertexBlendMatrixIndex))
  1277.         {
  1278.             Source=m_caps.MaxVertexBlendMatrixIndex;
  1279.             m_pchCurrent+=strlen(k_KeywordMaxVertexBlendMatrixIndex);
  1280.         }
  1281.         else if ( NextStringIs(k_KeywordMaxPrimitiveCount))
  1282.         {
  1283.             Source=m_caps.MaxPrimitiveCount;
  1284.             m_pchCurrent+=strlen(k_KeywordMaxPrimitiveCount);
  1285.         }
  1286.         else if ( NextStringIs(k_KeywordMaxVertexIndex))
  1287.         {
  1288.             Source=m_caps.MaxVertexIndex;
  1289.             m_pchCurrent+=strlen(k_KeywordMaxVertexIndex);
  1290.         }
  1291.         else if ( NextStringIs(k_KeywordMaxStreams))
  1292.         {
  1293.             Source=m_caps.MaxStreams;
  1294.             m_pchCurrent+=strlen(k_KeywordMaxStreams);
  1295.         }
  1296.         else if ( NextStringIs(k_KeywordMaxStreamStride))
  1297.         {
  1298.             Source=m_caps.MaxStreamStride;
  1299.             m_pchCurrent+=strlen(k_KeywordMaxStreamStride);
  1300.         }
  1301.         else if ( NextStringIs(k_KeywordVertexShaderVersion))
  1302.         {
  1303.             Source=m_caps.VertexShaderVersion;
  1304.             m_pchCurrent+=strlen(k_KeywordVertexShaderVersion);
  1305.         }
  1306.         else if ( NextStringIs(k_KeywordMaxVertexShaderConst))
  1307.         {
  1308.             Source=m_caps.MaxVertexShaderConst;
  1309.             m_pchCurrent+=strlen(k_KeywordMaxVertexShaderConst);
  1310.         }
  1311.         else if ( NextStringIs(k_KeywordPixelShaderVersion))
  1312.         {
  1313.             Source=m_caps.PixelShaderVersion;
  1314.             m_pchCurrent+=strlen(k_KeywordPixelShaderVersion);
  1315.         }
  1316.         else if (NextStringIs(k_KeywordVideoram))
  1317.         {
  1318.             Source=m_VideoMemory;
  1319.             m_pchCurrent+=8;
  1320.         }
  1321.         else if (NextStringIs(k_KeywordSubsysid))
  1322.         {
  1323.             Source=m_AdapterId.SubSysId;
  1324.             m_pchCurrent+=8;
  1325.         }
  1326.         else if (NextStringIs(k_KeywordRevision))
  1327.         {
  1328.             Source=m_AdapterId.Revision;
  1329.             m_pchCurrent+=8;
  1330.         }
  1331.         else if (NextStringIs(k_KeywordGuid))
  1332.         {
  1333.             Type=1;
  1334.             m_pchCurrent+=4;
  1335.         }
  1336.         else if (NextStringIs(k_KeywordDriver))
  1337.         {
  1338.             Type=2;
  1339.             m_pchCurrent+=6;
  1340.         }
  1341.         else if (NextStringIs(k_KeywordOs))
  1342.         {
  1343.             OSVERSIONINFO osinfo;
  1344.             osinfo.dwOSVersionInfoSize=sizeof(osinfo);
  1345.             GetVersionEx( &osinfo );
  1346.  
  1347.             if( osinfo.dwPlatformId==VER_PLATFORM_WIN32_NT )
  1348.             {
  1349.                 if( osinfo.dwMajorVersion==5 && osinfo.dwMinorVersion==2 )
  1350.                     Source=6;  // Win2003
  1351.                 else
  1352.                 {
  1353.                     Source=5;
  1354.                     if( osinfo.dwMajorVersion==5 && osinfo.dwBuildNumber<2600 )
  1355.                         Source=4;
  1356.                 }
  1357.             }
  1358.             else
  1359.             {
  1360.                 Source=3;
  1361.                 if( (osinfo.dwBuildNumber&0xffff)<=2222 )
  1362.                     Source=2;
  1363.                 if( (osinfo.dwBuildNumber&0xffff)<=1998 )
  1364.                     Source=1;
  1365.                 if( (osinfo.dwBuildNumber&0xffff)<=950 )
  1366.                     Source=0;
  1367.             }
  1368.             Type=3;
  1369.             m_pchCurrent+=2;
  1370.         }
  1371.         else
  1372.         {
  1373.             return "Unknown value";
  1374.         }
  1375.  
  1376.         SkipSpace();
  1377.  
  1378.         if( *(WORD*)m_pchCurrent=='==' )
  1379.         {
  1380.             m_pchCurrent+=2;
  1381.             Compare=0;
  1382.         }
  1383.         else
  1384.         {
  1385.             if( *(WORD*)m_pchCurrent=='=!' )
  1386.             {
  1387.                 m_pchCurrent+=2;
  1388.                 Compare=1;
  1389.             }
  1390.             else
  1391.             {
  1392.                 if( *(WORD*)m_pchCurrent=='><' )
  1393.                 {
  1394.                     m_pchCurrent+=2;
  1395.                     Compare=1;
  1396.                 }
  1397.                 else
  1398.                 {
  1399.                     if( *(WORD*)m_pchCurrent=='>=' )
  1400.                     {
  1401.                         m_pchCurrent+=2;
  1402.                         Compare=4;
  1403.                     }
  1404.                     else
  1405.                     {
  1406.                         if( *(WORD*)m_pchCurrent=='<=' )
  1407.                         {
  1408.                             m_pchCurrent+=2;
  1409.                             Compare=5;
  1410.                         }
  1411.                         else
  1412.                         {
  1413.                             if( *(WORD*)m_pchCurrent=='=<' )
  1414.                             {
  1415.                                 m_pchCurrent+=2;
  1416.                                 Compare=5;
  1417.                             }
  1418.                             else
  1419.                             {
  1420.                                 if( *(WORD*)m_pchCurrent=='=>' )
  1421.                                 {
  1422.                                     m_pchCurrent+=2;
  1423.                                     Compare=4;
  1424.                                 }
  1425.                                 else
  1426.                                 {
  1427.                                     if( *m_pchCurrent=='=' )
  1428.                                     {
  1429.                                         m_pchCurrent+=1;
  1430.                                         Compare=0;
  1431.                                     }
  1432.                                     else
  1433.                                     {
  1434.                                         if( *m_pchCurrent=='>' )
  1435.                                         {
  1436.                                             m_pchCurrent+=1;
  1437.                                             Compare=2;
  1438.                                         }
  1439.                                         else
  1440.                                         {
  1441.                                             if( *m_pchCurrent=='<' )
  1442.                                             {
  1443.                                                 m_pchCurrent+=1;
  1444.                                                 Compare=3;
  1445.                                             }
  1446.                                             else
  1447.                                             {
  1448.                                                 if ( *m_pchCurrent=='&' )
  1449.                                                 {
  1450.                                                     m_pchCurrent+=1;
  1451.                                                     Compare=6;
  1452.                                                 }
  1453.                                                 else
  1454.                                                 {
  1455.                                                     return "Unknown operator";
  1456.                                                 }
  1457.                                             }
  1458.                                         }
  1459.                                     }
  1460.                                 }
  1461.                             }
  1462.                         }
  1463.                     }
  1464.                 }
  1465.             }
  1466.         }
  1467.  
  1468.         SkipSpace();
  1469.  
  1470.         if( Type==1 )                               // GUID  D7B71F83-6340-11CF-4C73-0100A7C2C935
  1471.         {
  1472.             if( Compare>1 )
  1473.             {
  1474.                 return "Only == or != allowed";
  1475.             }
  1476.  
  1477.             DWORD tempGUID[4];
  1478.  
  1479.             DWORD res=Get4Digits();
  1480.  
  1481.             if( res==-1 )
  1482.                 return "Invalid GUID";
  1483.  
  1484.             DWORD res2=Get4Digits();
  1485.  
  1486.             if( res2==-1 )
  1487.                 return "Invalid GUID";
  1488.  
  1489.             tempGUID[0] = (res<<16)+res2;
  1490.  
  1491.             if( *m_pchCurrent++!='-' )
  1492.             {
  1493.                 return "Invalid GUID";
  1494.             }
  1495.  
  1496.             res=Get4Digits();
  1497.  
  1498.             if( res==-1 )
  1499.                 return "Invalid GUID";
  1500.  
  1501.             if( *m_pchCurrent++!='-' )
  1502.             {
  1503.                 return "Invalid GUID";
  1504.             }
  1505.  
  1506.             res2=Get4Digits();
  1507.  
  1508.             if( res2==-1 )
  1509.                 return "Invalid GUID";
  1510.  
  1511.             tempGUID[1] = (res2<<16)+res;
  1512.  
  1513.             if( *m_pchCurrent++!='-' )
  1514.             {
  1515.                 return "Invalid GUID";
  1516.             }
  1517.  
  1518.             res=sGet4Digits();
  1519.  
  1520.             if( res==-1 )
  1521.                 return "Invalid GUID";
  1522.  
  1523.             if( *m_pchCurrent++!='-' )
  1524.             {
  1525.                 return "Invalid GUID";
  1526.             }
  1527.  
  1528.             res2=sGet4Digits();
  1529.  
  1530.             if( res2==-1 )
  1531.                 return "Invalid GUID";
  1532.  
  1533.             tempGUID[2] = (res2<<16)+res;
  1534.  
  1535.             res=sGet4Digits();
  1536.  
  1537.             if( res==-1 )
  1538.                 return "Invalid GUID";
  1539.  
  1540.             res2=sGet4Digits();
  1541.  
  1542.             if( res2==-1 )
  1543.                 return "Invalid GUID";
  1544.  
  1545.             tempGUID[3] = (res2<<16)+res;
  1546.  
  1547.             if( Compare==0 )
  1548.             {
  1549.                 if( 0==memcmp( tempGUID, &m_AdapterId.DeviceIdentifier, 16 ) )
  1550.                     return (char*)1;
  1551.                 else
  1552.                     return (char*)0;
  1553.             }
  1554.  
  1555.             if( 0!=memcmp( tempGUID, &m_AdapterId.DeviceIdentifier, 16 ) )
  1556.                 return (char*)1;
  1557.             else
  1558.                 return (char*)0;
  1559.  
  1560.         }
  1561.  
  1562.         if( Type==2 )                               // Driver 4.1.25.1111
  1563.         {
  1564.             LARGE_INTEGER Driver;
  1565.  
  1566.             DWORD result=GetNumber();
  1567.  
  1568.             if( result==-1 || *m_pchCurrent++!='.' )
  1569.                 return "Invalid driver number";
  1570.  
  1571.             DWORD result1=GetNumber();
  1572.  
  1573.             Driver.HighPart=(result<<16)+result1;
  1574.  
  1575.             if( result==-1 || *m_pchCurrent++!='.' )
  1576.                 return "Invalid driver number";
  1577.  
  1578.             result=GetNumber();
  1579.  
  1580.             if( result==-1 || *m_pchCurrent++!='.' )
  1581.                 return "Invalid driver number";
  1582.  
  1583.             result1=GetNumber();
  1584.  
  1585.             Driver.LowPart=(result<<16)+result1;
  1586.  
  1587.             if( result==-1 )
  1588.                 return "Invalid driver number";
  1589.  
  1590.             __int64 rhs = *(__int64*)&Driver;
  1591.             __int64 lhs = *(__int64*)&m_AdapterId.DriverVersion;
  1592.  
  1593.             switch( Compare )
  1594.             {
  1595.             case 0:                                 // ==
  1596.                 if( lhs==rhs )
  1597.                     return (char*)1;
  1598.                 else
  1599.                     return (char*)0;
  1600.             case 1:                                 // !=
  1601.                 if( lhs!=rhs )
  1602.                     return (char*)1;
  1603.                 else
  1604.                     return (char*)0;
  1605.             case 2:                                 // >
  1606.                 if( lhs>rhs )
  1607.                     return (char*)1;
  1608.                 else
  1609.                     return (char*)0;
  1610.             case 3:                                 // <
  1611.                 if( lhs<rhs )
  1612.                     return (char*)1;
  1613.                 else
  1614.                     return (char*)0;
  1615.             case 4:                                 // >=
  1616.                 if( lhs>=rhs )
  1617.                     return (char*)1;
  1618.                 else
  1619.                     return (char*)0;
  1620.             case 5:                                 // <=
  1621.                 if( lhs<=rhs )
  1622.                     return (char*)1;
  1623.                 else
  1624.                     return (char*)0;
  1625.             }
  1626.  
  1627.             return "Invalid";
  1628.         }
  1629.         //
  1630.         // Get Value (or OS)
  1631.         //
  1632.         DWORD Value;
  1633.  
  1634.         if( Type==3 )
  1635.         {
  1636.             if (NextStringIs(k_KeywordWin95))
  1637.             {
  1638.                 Value=0;
  1639.                 m_pchCurrent+=5;            
  1640.             }
  1641.             else
  1642.             {
  1643.                 if (NextStringIs(k_KeywordWin98))
  1644.                 {
  1645.                     Value=1;
  1646.                     m_pchCurrent+=5;            
  1647.                 }
  1648.                 else
  1649.                 {
  1650.                     if (NextStringIs(k_KeywordWin98se))
  1651.                     {
  1652.                         Value=2;
  1653.                         m_pchCurrent+=7;
  1654.                     }
  1655.                     else
  1656.                     {
  1657.                         if (NextStringIs(k_KeywordWinme))
  1658.                         {
  1659.                             Value=3;
  1660.                             m_pchCurrent+=5;
  1661.                         }
  1662.                         else
  1663.                         {
  1664.                             if (NextStringIs(k_KeywordWin2k))
  1665.                             {
  1666.                                 Value=4;
  1667.                                 m_pchCurrent+=5;
  1668.                             }
  1669.                             else
  1670.                             {
  1671.                                 if (NextStringIs(k_KeywordWinxp))
  1672.                                 {
  1673.                                     Value=5;
  1674.                                     m_pchCurrent+=5;            
  1675.                                 }
  1676.                                 else
  1677.                                 {
  1678.                                     if (NextStringIs(k_KeywordWin2003))
  1679.                                     {
  1680.                                         Value=6;
  1681.                                         m_pchCurrent+=7;
  1682.                                     }
  1683.                                     else
  1684.                                     {
  1685.                                         return "Unknown OS";
  1686.                                     }
  1687.                                 }
  1688.                             }
  1689.                         }
  1690.                     }
  1691.                 }
  1692.             }
  1693.         }
  1694.         else
  1695.         {
  1696.             Value=GetNumber();
  1697.  
  1698.             if( Value==-1 )
  1699.             {
  1700.                 return "Number expected";
  1701.             }
  1702.         }
  1703.  
  1704.         switch( Compare )
  1705.         {
  1706.         case 0:                                 // ==
  1707.             if( Source==Value )
  1708.                 return (char*)1;
  1709.             else
  1710.                 return (char*)0;
  1711.         case 1:                                 // !=
  1712.             if( Source!=Value )
  1713.                 return (char*)1;
  1714.             else
  1715.                 return (char*)0;
  1716.         case 2:                                 // >
  1717.             if( Source>Value )
  1718.                 return (char*)1;
  1719.             else
  1720.                 return (char*)0;
  1721.         case 3:                                 // <
  1722.             if( Source<Value )
  1723.                 return (char*)1;
  1724.             else
  1725.                 return (char*)0;
  1726.         case 4:                                 // >=
  1727.             if( Source>=Value )
  1728.                 return (char*)1;
  1729.             else
  1730.                 return (char*)0;
  1731.         case 5:                                 // <=
  1732.             if( Source<=Value )
  1733.                 return (char*)1;
  1734.             else
  1735.                 return (char*)0;
  1736.  
  1737.         case 6:                                 // &
  1738.             if ( Source & Value )
  1739.                 return (char*)1;
  1740.             else
  1741.                 return (char*)0;
  1742.         }
  1743.  
  1744.         return "Invalid";
  1745.     }
  1746.  
  1747.     bool CConfigDatabase::Load( WCHAR* FileName,
  1748.                                    const SOUND_DEVICE& soundDevice,
  1749.                                    const D3DADAPTER_IDENTIFIER9& DDid,
  1750.                                    const D3DCAPS9& caps,
  1751.                                    DWORD SystemMemory,
  1752.                                    DWORD VideoMemory,
  1753.                                    DWORD CPUSpeed )
  1754.     {
  1755.         if (m_pDevice == NULL)
  1756.         {
  1757.             m_pDevice = new CPropertySet( *this );
  1758.         }
  1759.         if (m_pRequirements == NULL)
  1760.         {
  1761.             m_pRequirements = new CPropertySet( *this );
  1762.         }
  1763.  
  1764.         //
  1765.         // Setup return pointers
  1766.         //
  1767.         m_SoundDevice = soundDevice;
  1768.         m_CPUSpeed = CPUSpeed;
  1769.         m_SystemMemory = SystemMemory;
  1770.         m_VideoMemory = VideoMemory;
  1771.         m_AdapterId = DDid;
  1772.         m_caps = caps;
  1773.         m_fError = false;
  1774.         //
  1775.         // If driver version is 0.0.0.0 try and read from driver .dll
  1776.         //
  1777.         if( (m_AdapterId.DriverVersion.HighPart|m_AdapterId.DriverVersion.LowPart) == 0 )
  1778.         {
  1779.             VS_FIXEDFILEINFO ffi;
  1780.  
  1781.             DWORD dwHandle;
  1782.             DWORD cchver = GetFileVersionInfoSizeA( m_AdapterId.Driver, &dwHandle );
  1783.             if( cchver!=0 ) 
  1784.             {
  1785.                 char* pver = new char[cchver];
  1786.  
  1787.                 BOOL bret = GetFileVersionInfoA( m_AdapterId.Driver, dwHandle, cchver, pver );
  1788.  
  1789.                 if( bret ) 
  1790.                 {
  1791.                     UINT uLen;
  1792.                     void *pbuf;
  1793.  
  1794.                     bret = VerQueryValueA( pver, "\\", &pbuf, &uLen );
  1795.  
  1796.                     if( bret ) 
  1797.                     {
  1798.                         memcpy( &ffi, pbuf, sizeof(VS_FIXEDFILEINFO) );
  1799.  
  1800.                         m_AdapterId.DriverVersion.HighPart=ffi.dwFileVersionMS;
  1801.                         m_AdapterId.DriverVersion.LowPart=ffi.dwFileVersionLS;
  1802.                     }
  1803.                 }
  1804.  
  1805.                 delete [] pver;
  1806.             }
  1807.         }
  1808.         //
  1809.         // Try and find video card file
  1810.         //
  1811.         HANDLE hFile = CreateFile( FileName, GENERIC_READ, FILE_SHARE_READ,NULL, OPEN_EXISTING, 0, NULL );
  1812.  
  1813.         if( hFile == INVALID_HANDLE_VALUE )
  1814.         {
  1815.             WCHAR wszBadFile[MAX_PATH];
  1816.             WCHAR wszErrorMsg[MAX_PATH+128];
  1817.             static char szErrorMsg[MAX_PATH+128];
  1818.             GetCurrentDirectory( MAX_PATH, wszBadFile );
  1819.             lstrcatW( wszBadFile, L"\\" );
  1820.             lstrcatW( wszBadFile, FileName );
  1821.             swprintf( wszErrorMsg, L"Cannot find '%s'", wszBadFile );
  1822.  
  1823.             // Convert to MBCS
  1824.             WideCharToMultiByte( CP_ACP, 0, wszErrorMsg, -1, szErrorMsg, MAX_PATH+128, NULL, NULL );
  1825.  
  1826.             m_ErrorString = szErrorMsg;
  1827.             return false;
  1828.         }
  1829.  
  1830.         //
  1831.         // Read file in
  1832.         //
  1833.         DWORD Size=GetFileSize( hFile, NULL );
  1834.         DWORD Len;
  1835.         m_pchFile= new char[Size+16];                       // Some extra room for string compares
  1836.         BOOL bSuccess = ReadFile( hFile, m_pchFile, Size, &Len, NULL );
  1837.         CloseHandle( hFile );
  1838.         if( !bSuccess )
  1839.         {
  1840.             delete [] m_pchFile;
  1841.             return false;
  1842.         }
  1843.  
  1844.         m_pchFile[Size]=13;                                     // Make sure last line ends with CR.
  1845.         m_pchCurrent=m_pchFile;
  1846.         m_pchCurrentLine=m_pchCurrent;
  1847.         m_LineNumber=1;
  1848.         m_pchEndOfFile=m_pchFile+Size;
  1849.  
  1850.         if (!DoRequirements())
  1851.         {
  1852.             delete [] m_pchFile;
  1853.             return false;
  1854.         }
  1855.  
  1856.         m_pchCurrent=m_pchFile;
  1857.         m_pchCurrentLine=m_pchCurrent;
  1858.         m_LineNumber=1;
  1859.         if (!DoPropertySets())
  1860.         {
  1861.             delete [] m_pchFile;
  1862.             return false;
  1863.         }
  1864.  
  1865.         if (!DoPreApplyToAll())
  1866.         {
  1867.             delete [] m_pchFile;
  1868.             return false;
  1869.         }
  1870.  
  1871.         // Save the location marker after pre-ApplyToAll block.
  1872.         // Later, audio vendor parsing should begin here too.
  1873.         char *pchAfterPreApplyToAll = m_pchCurrent;
  1874.         char *pchLineAfterPreApplyToAll = m_pchCurrentLine;
  1875.         int nLineNumberAfterPreApplyToAll = m_LineNumber;
  1876.         if (!DoDisplayVendorAndDevice())
  1877.         {
  1878.             delete [] m_pchFile;
  1879.             return false;
  1880.         }
  1881.         // Save the location marker after display vendor section
  1882.         // to help parse the post-applytoall block.
  1883.         char *pchAfterDisplayVendor = m_pchCurrent;
  1884.         char *pchLineAfterDisplayVendor = m_pchCurrentLine;
  1885.         DWORD nLineNumberAfterDisplayVendor = m_LineNumber;
  1886.  
  1887.         // Restore text pointers to the location after the pre-
  1888.         // ApplyToAll block.
  1889.         m_pchCurrent = pchAfterPreApplyToAll;
  1890.         m_pchCurrentLine = pchLineAfterPreApplyToAll;
  1891.         m_LineNumber = nLineNumberAfterPreApplyToAll;
  1892.         if (!DoSoundVendorAndDevice())
  1893.         {
  1894.             delete [] m_pchFile;
  1895.             return false;
  1896.         }
  1897.  
  1898.         // Start post-ApplyToAll parsing at the end of
  1899.         // both display and audio sections.
  1900.         m_pchCurrent = max( m_pchCurrent, pchAfterDisplayVendor );
  1901.         m_pchCurrentLine = max( m_pchCurrentLine, pchLineAfterDisplayVendor );
  1902.         m_LineNumber = max( m_LineNumber, nLineNumberAfterDisplayVendor );
  1903.         if (!DoPostApplyToAll())
  1904.         {
  1905.             delete [] m_pchFile;
  1906.             return false;
  1907.         }
  1908.  
  1909.         //
  1910.         // Clean up and retrun
  1911.         //
  1912.         delete [] m_pchFile;
  1913.         return true;
  1914.     }
  1915.  
  1916.     CConfigDatabase::CConfigDatabase()
  1917.     {
  1918.         m_pDevice = 0;
  1919.         m_pRequirements = 0;
  1920.     }
  1921.  
  1922.     CConfigDatabase::~CConfigDatabase()
  1923.     {
  1924.         delete m_pDevice;
  1925.         delete m_pRequirements;
  1926.  
  1927.         std::map<std::string, CPropertySet*>::iterator it, end;
  1928.         it = m_mapNameToPropertySet.begin();
  1929.         end = m_mapNameToPropertySet.end();
  1930.         while (it != end)
  1931.         {
  1932.             delete (*it).second;
  1933.             ++it;
  1934.         }
  1935.     }
  1936.  
  1937.     bool CConfigDatabase::DoPreApplyToAll()
  1938.     {
  1939.         do
  1940.         {
  1941.             if ( NextStringIs(k_KeywordApplyToAll))
  1942.             {
  1943.                 SkipToNextLine();
  1944.                 if (!DoPropertySet(m_pDevice))
  1945.                 {
  1946.                     return false;
  1947.                 }
  1948.             }
  1949.             else if( NextStringIs(k_KeywordDisplayVendor) ||
  1950.                      NextStringIs(k_KeywordAudioVendor) )
  1951.             {
  1952.                 break;
  1953.             }
  1954.  
  1955.             SkipToNextLine();
  1956.  
  1957.         } while( m_pchCurrent<m_pchEndOfFile );
  1958.  
  1959.         return true;
  1960.     }
  1961.  
  1962.     bool CConfigDatabase::DoPostApplyToAll()
  1963.     {
  1964.         do
  1965.         {
  1966.             if ( NextStringIs(k_KeywordApplyToAll))
  1967.             {
  1968.                 SkipToNextLine();
  1969.                 if (!DoPropertySet(m_pDevice))
  1970.                 {
  1971.                     return false;
  1972.                 }
  1973.             }
  1974.  
  1975.             SkipToNextLine();
  1976.  
  1977.         } while( m_pchCurrent<m_pchEndOfFile );
  1978.  
  1979.         return true;
  1980.     }
  1981.  
  1982.  
  1983.     bool CConfigDatabase::DoPropertySets()
  1984.     {
  1985.         do
  1986.         {
  1987.             if ( NextStringIs(k_KeywordPropertySet))
  1988.             {
  1989.                 m_pchCurrent+=11;
  1990.  
  1991.                 SkipSpace();
  1992.  
  1993.                 if ( *m_pchCurrent=='=' )
  1994.                 {
  1995.                     m_pchCurrent++;
  1996.  
  1997.                     char* pszName = GetString();
  1998.                     if (!pszName)
  1999.                     {
  2000.                         return false;
  2001.                     }
  2002.  
  2003.                     std::string strName = pszName;
  2004.  
  2005.                     SkipToNextLine();
  2006.                     CPropertySet* pSet = new CPropertySet(*this);
  2007.                     if (!DoPropertySet(pSet))
  2008.                     {
  2009.                         delete pSet;
  2010.                         return false;
  2011.                     }
  2012.  
  2013.                     m_mapNameToPropertySet[strName] = pSet;
  2014.  
  2015.                 }
  2016.                 else
  2017.                 {
  2018.                     SyntaxError("Missing =");
  2019.                     return false;
  2020.                 }
  2021.             }
  2022.             else if( (NextStringIs(k_KeywordDisplayVendor)) || (NextStringIs(k_KeywordAudioVendor))
  2023.                 || (NextStringIs(k_KeywordApplyToAll)) )
  2024.             {
  2025.                 break;
  2026.             }
  2027.  
  2028.             SkipToNextLine();
  2029.  
  2030.         } while( m_pchCurrent<m_pchEndOfFile );
  2031.  
  2032.         return true;
  2033.     }
  2034.  
  2035.     bool CConfigDatabase::DoDisplayVendorAndDevice()
  2036.     {
  2037.         //
  2038.         // Find correct VendorID
  2039.         //
  2040.         DWORD Vendor=-1;
  2041.         do
  2042.         {
  2043.             if (NextStringIs(k_KeywordDisplayVendor))
  2044.             {
  2045.                 m_pchCurrent+=13;
  2046.  
  2047.                 SkipSpace();
  2048.  
  2049.                 if( *m_pchCurrent=='=' )
  2050.                 {
  2051.                     m_pchCurrent++;
  2052.  
  2053.                     if (NextStringIs(k_KeywordUnknown))
  2054.                     {
  2055.                         Vendor=m_AdapterId.VendorId;
  2056.                         break;
  2057.                     }
  2058.  
  2059.                     DWORD tempVendor=GetNumber();                       // Will be -1 if error
  2060.  
  2061.                     if( tempVendor==m_AdapterId.VendorId )
  2062.                     {
  2063.                         Vendor=tempVendor;
  2064.                         break;
  2065.                     }
  2066.                 }
  2067.             }
  2068.             else if (NextStringIs(k_KeywordApplyToAll))
  2069.             {
  2070.                 break;
  2071.             }
  2072.  
  2073.             SkipToNextLine();
  2074.  
  2075.         } while( m_pchCurrent<m_pchEndOfFile );
  2076.         //
  2077.         // Deal with Unknown VendorID
  2078.         //
  2079.         if( Vendor==-1 )
  2080.         {
  2081.             return true;
  2082.         }
  2083.         //
  2084.         // Get Vendor Name
  2085.         //
  2086.         const char* pszVendor = GetString();
  2087.         if (!pszVendor)
  2088.         {
  2089.             return false;
  2090.         }
  2091.         m_VendorString = pszVendor;
  2092.  
  2093.         //
  2094.         // Skip over any other vendor names (Some devices have multiple vendors)
  2095.         //
  2096.         do
  2097.         {
  2098.             SkipToNextLine();
  2099.  
  2100.             if (!NextStringIs(k_KeywordDisplayVendor))
  2101.             {
  2102.                 SkipSpace();
  2103.  
  2104.                 if( *m_pchCurrent>='0' && *m_pchCurrent<='9' )
  2105.                 {
  2106.                     break;
  2107.                 }
  2108.  
  2109.                 if( *m_pchCurrent!=13 && *(WORD*)m_pchCurrent!='//' )       // Ignore comments and blank lines
  2110.                 {
  2111.                     //
  2112.                     // If we find a line that is not a comment or vendor before
  2113.                     // the first device, it must be the start of a property set.
  2114.                     //
  2115.                     if (!DoPropertySet(m_pDevice))
  2116.                     {
  2117.                         return false;
  2118.                     }
  2119.                 }
  2120.             }
  2121.  
  2122.         } while( m_pchCurrent<m_pchEndOfFile );
  2123.         //
  2124.         // Now search for DeviceID  (Until next vendor or end of file is found)
  2125.         //
  2126.         DWORD DeviceID=-1;
  2127.         do
  2128.         {
  2129.             if (NextStringIs(k_KeywordDisplayVendor))
  2130.             {
  2131.                 break;
  2132.             }
  2133.  
  2134.             if (NextStringIs(k_KeywordUnknown))
  2135.             {
  2136.                 DeviceID=m_AdapterId.DeviceId;
  2137.                 m_pchCurrent += strlen (k_KeywordUnknown);
  2138.                 SkipSpace();
  2139.                 break;
  2140.             }
  2141.  
  2142.             SkipSpace();
  2143.  
  2144.             if( *m_pchCurrent>='0' && *m_pchCurrent<='9' )
  2145.             {
  2146.                 DWORD tempDeviceID=GetNumber();
  2147.  
  2148.                 if( tempDeviceID==m_AdapterId.DeviceId )
  2149.                 {
  2150.                     DeviceID=tempDeviceID;
  2151.                     break;
  2152.                 }
  2153.             }
  2154.  
  2155.             SkipToNextLine();
  2156.  
  2157.         } while( m_pchCurrent<m_pchEndOfFile );
  2158.         //
  2159.         // Deal with unknown DeviceID
  2160.         //
  2161.         if( DeviceID==-1 )
  2162.         {
  2163.             return true;
  2164.         }
  2165.         //
  2166.         // Get Device Name
  2167.         //
  2168.         if( *m_pchCurrent!='=' )
  2169.         {
  2170.             SyntaxError( "xxx = Device Name expected" );
  2171.             return false;
  2172.         }
  2173.         //
  2174.         // Add the device name
  2175.         //
  2176.         m_pchCurrent++;
  2177.  
  2178.         char* pszDevice = GetString();
  2179.         if (!pszDevice)
  2180.         {
  2181.             return false;
  2182.         }
  2183.         m_DeviceString = pszDevice;
  2184.  
  2185.         //
  2186.         // Now add flags until break is found
  2187.         //
  2188.         SkipToNextLine();
  2189.         if (!DoPropertySet(m_pDevice))
  2190.         {
  2191.             return false;
  2192.         }
  2193.  
  2194.         return true;
  2195.     }
  2196.  
  2197.     bool CConfigDatabase::DoSoundVendorAndDevice()
  2198.     {
  2199.         //
  2200.         // Find correct VendorID
  2201.         //
  2202.         DWORD Vendor=-1;
  2203.         do
  2204.         {
  2205.             if (NextStringIs(k_KeywordAudioVendor))
  2206.             {
  2207.                 m_pchCurrent+=11;
  2208.  
  2209.                 SkipSpace();
  2210.  
  2211.                 if( *m_pchCurrent=='=' )
  2212.                 {
  2213.                     m_pchCurrent++;
  2214.  
  2215.                     if (NextStringIs(k_KeywordUnknown))
  2216.                     {
  2217.                         Vendor=m_SoundDevice.VendorID;
  2218.                         break;
  2219.                     }
  2220.  
  2221.                     DWORD tempVendor=GetNumber();                       // Will be -1 if error
  2222.  
  2223.                     if( tempVendor==m_SoundDevice.VendorID )
  2224.                     {
  2225.                         Vendor=tempVendor;
  2226.                         break;
  2227.                     }
  2228.                 }
  2229.             }
  2230.             else if (NextStringIs(k_KeywordApplyToAll))
  2231.             {
  2232.                 break;
  2233.             }
  2234.  
  2235.             SkipToNextLine();
  2236.  
  2237.         } while( m_pchCurrent<m_pchEndOfFile );
  2238.         //
  2239.         // Deal with Unknown VendorID
  2240.         //
  2241.         if( Vendor==-1 )
  2242.         {
  2243.             return true;
  2244.         }
  2245.         //
  2246.         // Get Vendor Name
  2247.         //
  2248.         const char* pszVendor = GetString();
  2249.         if (!pszVendor)
  2250.         {
  2251.             return false;
  2252.         }
  2253.         m_SoundVendorString = pszVendor;
  2254.  
  2255.         //
  2256.         // Skip over any other vendor names (Some devices have multiple vendors)
  2257.         //
  2258.         do
  2259.         {
  2260.             SkipToNextLine();
  2261.  
  2262.             if (!NextStringIs(k_KeywordAudioVendor))
  2263.             {
  2264.                 SkipSpace();
  2265.  
  2266.                 if( *m_pchCurrent>='0' && *m_pchCurrent<='9' )
  2267.                 {
  2268.                     break;
  2269.                 }
  2270.  
  2271.                 if( *m_pchCurrent!=13 && *(WORD*)m_pchCurrent!='//' )       // Ignore comments and blank lines
  2272.                 {
  2273.                     //
  2274.                     // If we find a line that is not a comment or vendor before
  2275.                     // the first device, it must be the start of a property set.
  2276.                     //
  2277.                     if (!DoPropertySet(m_pDevice))
  2278.                     {
  2279.                         return false;
  2280.                     }
  2281.                 }
  2282.             }
  2283.  
  2284.         } while( m_pchCurrent<m_pchEndOfFile );
  2285.         //
  2286.         // Now search for DeviceID  (Until next vendor or end of file is found)
  2287.         //
  2288.         DWORD DeviceID=-1;
  2289.         do
  2290.         {
  2291.             if (NextStringIs(k_KeywordAudioVendor) || NextStringIs(k_KeywordDisplayVendor))
  2292.             {
  2293.                 break;
  2294.             }
  2295.  
  2296.             if (NextStringIs(k_KeywordUnknown))
  2297.             {
  2298.                 DeviceID=m_SoundDevice.DeviceID;
  2299.                 m_pchCurrent += strlen (k_KeywordUnknown);
  2300.                 SkipSpace();
  2301.                 break;
  2302.             }
  2303.  
  2304.             SkipSpace();
  2305.  
  2306.             if( *m_pchCurrent>='0' && *m_pchCurrent<='9' )
  2307.             {
  2308.                 DWORD tempDeviceID=GetNumber();
  2309.  
  2310.                 if( tempDeviceID==m_SoundDevice.DeviceID )
  2311.                 {
  2312.                     DeviceID=tempDeviceID;
  2313.                     break;
  2314.                 }
  2315.             }
  2316.  
  2317.             SkipToNextLine();
  2318.  
  2319.         } while( m_pchCurrent<m_pchEndOfFile );
  2320.         //
  2321.         // Deal with unknown DeviceID
  2322.         //
  2323.         if( DeviceID==-1 )
  2324.         {
  2325.             return true;
  2326.         }
  2327.         //
  2328.         // Get Device Name
  2329.         //
  2330.         if( *m_pchCurrent!='=' )
  2331.         {
  2332.             SyntaxError( "xxx = Device Name expected" );
  2333.             return false;
  2334.         }
  2335.         //
  2336.         // Add the device name
  2337.         //
  2338.         m_pchCurrent++;
  2339.  
  2340.         char* pszDevice = GetString();
  2341.         if (!pszDevice)
  2342.         {
  2343.             return false;
  2344.         }
  2345.         m_SoundDeviceString = pszDevice;
  2346.  
  2347.         //
  2348.         // Now add flags until break is found
  2349.         //
  2350.         SkipToNextLine();
  2351.         if (!DoPropertySet(m_pDevice))
  2352.         {
  2353.             return false;
  2354.         }
  2355.  
  2356.         return true;
  2357.     }
  2358.  
  2359.     bool CConfigDatabase::DoRequirements()
  2360.     {
  2361.         //
  2362.         // Find correct Requirements section
  2363.         //
  2364.         do
  2365.         {
  2366.             if (NextStringIs(k_KeywordRequirements))
  2367.             {
  2368.                 break;
  2369.             }
  2370.             SkipToNextLine();
  2371.  
  2372.         } while( m_pchCurrent<m_pchEndOfFile );
  2373.         //
  2374.         // No Requirment section?
  2375.         //
  2376.         if( m_pchCurrent>=m_pchEndOfFile )
  2377.         {
  2378.             return true;
  2379.         }
  2380.         //
  2381.         // Get Requirements
  2382.         //
  2383.         SkipToNextLine();
  2384.         if (!DoPropertySet(m_pRequirements))
  2385.         {
  2386.             return false;
  2387.         }
  2388.  
  2389.         return true;
  2390.     }
  2391.  
  2392.     bool CConfigDatabase::DoPropertySet(CPropertySet* pPropertySet)
  2393.     {
  2394.         //
  2395.         // Now add flags until break is found
  2396.         //
  2397.         const int k_MaxNestedIf = 256;                              // Max levels of nesting
  2398.         int NestedIf[k_MaxNestedIf];
  2399.         int IfPointer=0;                                            // Depth of IF's
  2400.         int SkippingIF=0;                                           // 0=Not in an IF, 1=In True if, 2=In false IF
  2401.         bool first = true;
  2402.  
  2403.         do
  2404.         {
  2405.             if (first)
  2406.             {
  2407.                 first = false;
  2408.             }
  2409.             else
  2410.             {
  2411.                 SkipToNextLine();
  2412.             }
  2413.  
  2414.             //
  2415.             // Check for unexpected keywords
  2416.             //
  2417.             if( NextStringIs(k_KeywordDisplayVendor) || NextStringIs(k_KeywordAudioVendor) || NextStringIs(k_KeywordRequirements) )
  2418.             {
  2419.                 return true;
  2420.             }
  2421.  
  2422.             SkipSpace();
  2423.  
  2424.             if( *m_pchCurrent!=13 && *(WORD*)m_pchCurrent!='//' )       // Ignore comments and blank lines
  2425.             {
  2426.  
  2427.                 if( *m_pchCurrent>='0' && *m_pchCurrent<='9' )      // Or the start of another device
  2428.                 {
  2429.                     continue;
  2430.                 }
  2431.  
  2432.                 if (NextStringIs(k_KeywordUnknown))             // Or unknown device clause
  2433.                 {
  2434.                     continue;
  2435.                 }
  2436.  
  2437.                 if (NextStringIs(k_KeywordBreak))
  2438.                 {
  2439.                     break;
  2440.                 }
  2441.  
  2442.                 if (NextStringIs(k_KeywordMaxOverallGraphicDetail))
  2443.                 {
  2444.                     m_pchCurrent += strlen(k_KeywordMaxOverallGraphicDetail);
  2445.  
  2446.                     //  This should be in the format: MaxOGD = N
  2447.                     //  Skip spaces, '='s.
  2448.                     SkipSpace();
  2449.                     if (*m_pchCurrent == '=')
  2450.                     {
  2451.                         m_pchCurrent++;
  2452.                     }
  2453.                     else
  2454.                     {
  2455.                         SyntaxError("Expecting \'=\', didn\'t get it");
  2456.                         return false;
  2457.                     }
  2458.                     SkipSpace();
  2459.  
  2460.                     //  We have the value in string format in m_pchCurrent and we need the
  2461.                     //  value in both string and numeric format. Doing a GetNumber then a
  2462.                     //  sprintf works best because it will keep extra spaces or comments out
  2463.                     //  of the string version.
  2464.  
  2465.                     DWORD dwMaxOGD = GetNumber();
  2466.                     if (dwMaxOGD != (DWORD)-1)
  2467.                     {
  2468.                         char maxValue[16];
  2469.                         char curValue[16] = "0";
  2470.  
  2471.                         sprintf(maxValue, "%d", dwMaxOGD);
  2472.                         if (m_pDevice->Get(k_KeywordOverallGraphicDetail, curValue, sizeof(curValue)))
  2473.                         {
  2474.                             DWORD dwOGD = atoi(curValue);
  2475.                             if (dwOGD > dwMaxOGD)
  2476.                             {
  2477.                                 //  Check the current graphic detail level. If its
  2478.                                 //  higher than the max, apply the max.
  2479.                                 std::map<std::string, CPropertySet*>::iterator it;
  2480.                                 it = m_mapOGDToPropertySet.find(maxValue);
  2481.                                 if (it == m_mapOGDToPropertySet.end())
  2482.                                 {
  2483.                                     SyntaxError("Unrecognized graphic detail");
  2484.                                     return false;
  2485.                                 }
  2486.                                 CPropertySet* pSet = (*it).second;
  2487.                                 ApplyPropertySet(m_pDevice, pSet);
  2488.                             }
  2489.                         }
  2490.                     }
  2491.                     else
  2492.                     {
  2493.                         SyntaxError("MaxOverallGraphicDetail did not specify a number!");
  2494.                         return false;
  2495.                     }
  2496.  
  2497.                     continue;
  2498.                 }
  2499.  
  2500.                 if (NextStringIs(k_KeywordIf))
  2501.                 {
  2502.                     m_pchCurrent+=2;
  2503.  
  2504.                     char* condition=GetCondition();
  2505.  
  2506.                     NestedIf[IfPointer++]=SkippingIF;
  2507.  
  2508.                     if( IfPointer==16 )
  2509.                     {
  2510.                         SyntaxError( "IF's nested too deep" );
  2511.                         return false;
  2512.                     }
  2513.  
  2514.                     if( condition==(char*)1 )                       // True?
  2515.                     {
  2516.                         if( SkippingIF!=2 )
  2517.                         {
  2518.                             SkippingIF=1;                           // If inside false if, keep skipping
  2519.                         }
  2520.                     }
  2521.                     else
  2522.                     {
  2523.                         if( condition==(char*)0 )                   // False?
  2524.                         {
  2525.                             SkippingIF=2;
  2526.                         }
  2527.                         else
  2528.                         {
  2529.                             if( condition )                         // m_fError
  2530.                             {
  2531.                                 SyntaxError( condition );
  2532.                                 return false;
  2533.                             }
  2534.                         }
  2535.                     }
  2536.                 }
  2537.                 else
  2538.                 {
  2539.                     if (NextStringIs(k_KeywordEndif))
  2540.                     {
  2541.                         if( IfPointer==0 )
  2542.                         {
  2543.                             SyntaxError( "Unexpected ENDIF" );
  2544.                             return false;
  2545.                         }
  2546.  
  2547.                         SkippingIF=NestedIf[--IfPointer];
  2548.                     }
  2549.                     else
  2550.                     {
  2551.                         if( 0==SkippingIF || 1==SkippingIF )                    // Add flag if not skipping in a IF
  2552.                         {
  2553.                             if ( NextStringIs(k_KeywordPropertySet))
  2554.                             {
  2555.                                 m_pchCurrent+=11;
  2556.  
  2557.                                 SkipSpace();
  2558.  
  2559.                                 if ( *m_pchCurrent=='=' )
  2560.                                 {
  2561.                                     m_pchCurrent++;
  2562.  
  2563.                                     char* pszName = GetString();
  2564.                                     if (!pszName)
  2565.                                     {
  2566.                                         return false;
  2567.                                     }
  2568.                                     std::string strName = pszName;
  2569.  
  2570.                                     std::map<std::string, CPropertySet*>::iterator it;
  2571.                                     it = m_mapNameToPropertySet.find(strName);
  2572.                                     if (it == m_mapNameToPropertySet.end())
  2573.                                     {
  2574.                                         SyntaxError("Unrecognized property set");
  2575.                                         return false;
  2576.                                     }
  2577.                                     CPropertySet* pSet = (*it).second;
  2578.                                     ApplyPropertySet(pPropertySet, pSet);
  2579.                                 }
  2580.                                 else
  2581.                                 {
  2582.                                     SyntaxError("Missing =");
  2583.                                     return false;
  2584.                                 }
  2585.                             }
  2586.                             else
  2587.                             {
  2588.                                 char* strErr=AddFlag(pPropertySet);  // Add this flag, check for duplicates
  2589.  
  2590.                                 if (strErr)
  2591.                                 {
  2592.                                     SyntaxError( strErr );
  2593.                                     return false;
  2594.                                 }
  2595.                             }
  2596.                         }
  2597.                     }
  2598.                 }
  2599.             }
  2600.  
  2601.         } while( m_pchCurrent<m_pchEndOfFile );
  2602.  
  2603.         //
  2604.         // Check for hanging endif
  2605.         //
  2606.         if( SkippingIF!=0 || IfPointer!=0 )
  2607.         {
  2608.             SyntaxError( "Bad IF/ENDIF" );
  2609.             return false;
  2610.         }
  2611.  
  2612.         return true;
  2613.     }
  2614.  
  2615.     void CConfigDatabase::ApplyPropertySet(CPropertySet* pSetDst, CPropertySet* pSetSrc)
  2616.     {
  2617.         std::vector<StringPair>::const_iterator it, end;
  2618.         it = pSetSrc->GetProperties().begin();
  2619.         end = pSetSrc->GetProperties().end();
  2620.         while (it != end)
  2621.         {
  2622.             const StringPair& pr = *it;
  2623.             pSetDst->Set(pr.first.c_str(), pr.second.c_str());
  2624.             ++it;
  2625.         }
  2626.     }
  2627.  
  2628. IConfigDatabase* IConfigDatabase::Create()
  2629. {
  2630.     CConfigDatabase* pRet = new CConfigDatabase();
  2631.     return pRet;
  2632. }
  2633.